/* key.h */
#ifndef __KEY_H__
#define __KEY_H__

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#ifdef __MICROLIB
#define assert(x)
#else
#include <assert.h>
#endif /* __MICROLIB */

typedef enum
{
    eKey_State_UnPressed = 0,          /*!< 未按下状态 */ 
    eKey_State_FirstPressedDown,   /*!< 进入长按状态之前的按下状态 */
    eKey_State_InLongPressedDownA, /*!< 长按A状态 */
    eKey_State_InLongPressedDownB, /*!< 长按B状态 */
} Key_State_T;

typedef enum
{
    eKey_Event_Nothing = 0,
    eKey_Event_PressedDownEdge,         /*!< 按下事件 */
    eKey_Event_PressedDownLongFirst,    /*!< 首次检测到长按事件 */
    eKey_Event_PressedDownLongContinue, /*!< 长按状态下的连击事件 */
    eKey_Event_PressedUpEdgeShort,      /*!< 短按弹起事件 */
    eKey_Event_PressedUpEdgeLong,       /*!< 长按弹起事件 */
} Key_Event_T;

/* Keep all the static variable and information for each key. */
typedef struct
{
    /* State. */
    Key_State_T PreState;
    Key_State_T CurState;

    /* Attr. */
    uint32_t PressedDownLongMaxFirst; /* To detect the start of long pressed. */
    uint32_t PressedDownLongMaxContinue;  /* To detect the continue long pressed. */

    /* Condition. */
    uint32_t PressedDownCounter; /* Count for the period that keeping the key pressed. */
    uint32_t PressedDownStepCounter;

} Key_Handler_T;

typedef struct
{
    /* Attr. */
    uint32_t FilterCountMax; /* The output would change if the new value keeps enough time. */

    /* Static. */
    uint32_t StableValue; /* Current output value. */
    uint32_t NextValue; /* Protential output value, would be change to output value if it keeps long enough. */
    uint32_t AccCounterForNextValue; /* Tick counter for nex value. */
} Filter_Handler_T;

void Filter_Init(Filter_Handler_T *handler, uint32_t initValue, uint32_t filterCount);
uint32_t Filter_GetFiltedOutput(Filter_Handler_T *handler, uint32_t curUnfiltedValue);

void Key_Init(Key_Handler_T *handler, uint32_t longDownCountFirst, uint32_t longDownCountStep);

/*!
 * @brief Update the state machine and get the new state.
 *
 * This function should be called periodically in timer module's ISR. It increases the counter and 
 * judges the new state.
 *
 * @param handler   A pointer to "Key_Handler_T" structure, representing this key.
 * @param isKeyDown Input the current key value.
 * 
 * @return The current state after processing the current key value.
 */
Key_State_T Key_GetState(Key_Handler_T *handler, bool isKeyDown);

/*!
 * @brief Check the update of state and pick out the action event.
 *
 * This function should be called immediately after the new state is created. It would also updates
 * the old state inside the function.
 *
 * @param handler A pointer to "Key_Handler_T" structure, representing this key.
 * 
 * @return The action event between previous state to current one.
 */
Key_Event_T Key_GetEvent(Key_Handler_T *handler);

#endif /* __KEY_H__ */

